#include "win32util.h"
#define WM_SENDSTRING WM_USER+100
#include "random.h"

Win32Util::Win32Util(QObject *parent): QObject(parent){}

QString Win32Util::getWindowTextW(HWND hwnd)
{
    int textLen = GetWindowTextLengthW(hwnd);

    wchar_t* buffer = new wchar_t[textLen + 1];

    GetWindowTextW(hwnd, buffer, textLen + 1);
    return QString::fromWCharArray(buffer);

}

int More(int mini,int maxi) //生成随机数函数
{
        //参数:1.区间最小值;2.区间最大值

    srand((unsigned)time(NULL)); //初始化随机数种子
    int impo=mini+rand()%(maxi-mini+1);

    return impo;
}

void Win32Util::moveMouse(int dual_X, int dual_Y)
{
    //参数：1.目的地X坐标 2.目的地Y坐标
    double goverX=0,goverY=0; //轨迹X,Y
    double factuX=1,factuY=1; //当前鼠标坐标
    double problem_X=double(dual_X),problem_Y=double(dual_Y); //目的地坐标
    double used=0;
    int always=0;//移动次数
    int Priya=0; //随机次数
    int Shah=More(16,20); //移动步长
    int own=1; //移动延时
    int ShahX=0,ShahY=0; //移动偏差X,移动偏差Y
    QString Kara;
    POINT Paid; //声明一个结构存放鼠标当前X Y坐标
    GetCursorPos(&Paid); //获取鼠标当前位置
    factuX=double(Paid.x);//把当前鼠标坐标转换成双浮点数
    factuY=double(Paid.y);

    if (abs(factuX-problem_X)>abs(factuY-problem_Y)){
        used=abs(factuX-problem_X);
    }else{
        used=abs(factuY-problem_Y);
    }

    goverX=(problem_X-factuX)/used;  //轨迹X
    goverY=(problem_Y-factuY)/used;  //轨迹Y
    while(factuX!=problem_X || factuY!=problem_Y)
    {
        always++;//移动次数
        factuX=factuX+goverX; //当前X坐标+轨迹X
        factuY=factuY+goverY; //当前Y坐标+轨迹Y
        if (always==Shah) //移动次数==移动步长
        {
            always=0; //移动次数
            Priya++; //随机次数
            Shah=More(16,20); //移动步长
            own=More(3,6); //移动延时
            if (Priya==4)
            {
                //每运行5次就随机产生一个随机偏差轨迹，模拟手动移动轨迹
                ShahX=More(-12,12); //移动偏差X
                ShahY=More(-9,9); //移动偏差Y
                Priya=0; //随机次数

            }
            int metics_X=int(factuX); //把算出来的坐标转换为整数
            int metics_Y=int(factuY);

            SetCursorPos(metics_X+ShahX,metics_Y+ShahY); //任意移动鼠标的API也可以是驱动键盘
            Sleep(own); //随机延迟
        }

        if (abs(factuX-problem_X)<=Shah && abs(factuY-problem_Y)<=Shah)
        {
            SetCursorPos(dual_X,dual_Y); //移动到终点附近后直接移动到终点
            //任意移动鼠标的API也可以是驱动键盘
            break;
        }
    }
}

void Win32Util::mouseLeftClick(bool isDoubleClick)
{
    Sleep(70);
    mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
    Sleep(70);
    mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    if(isDoubleClick){
        Sleep(70 + Random::getInstance()->getIntRandom(30));
        mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
        Sleep(70+ Random::getInstance()->getIntRandom(30));
        mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
    }
}

void Win32Util::mouseWheel(int length)
{
    Sleep(70);
    mouse_event(MOUSEEVENTF_WHEEL, 0, 0, length, 0);

}

void Win32Util::mouseRightClick()
{
     Sleep(70 + Random::getInstance()->getIntRandom(30));
    mouse_event(MOUSEEVENTF_RIGHTDOWN, 0, 0, 0, 0);
     Sleep(70 + Random::getInstance()->getIntRandom(30));
    mouse_event(MOUSEEVENTF_RIGHTUP, 0, 0, 0, 0);
}

void Win32Util::keyboardClick(byte keyCode)
{
    Sleep(70 + Random::getInstance()->getIntRandom(30));
    keybd_event(keyCode, 0, 0, 0);
    Sleep(70 + Random::getInstance()->getIntRandom(30));
    keybd_event(keyCode, 0, KEYEVENTF_KEYUP, 0);
}


void Win32Util::keyboardClick(QString message, bool isPaste)
{
    if(isPaste){
        QClipboard *clipboard = QApplication::clipboard();
        clipboard->setText(message);
        Sleep(70);
        keyboardClick(VK_CONTROL, 'V');
    }else{
        QByteArray arr=  message.toLatin1();
        DWORD sc, shift;
        char a;
        unsigned char vkey;
        for (int i = 0; i<arr.size(); i++)//模拟键盘输出str中的字符
        {
            a = arr.at(i);
            sc = OemKeyScan(a);
            shift = sc >> 16;
            vkey = MapVirtualKey(sc & 0xffff, 1);
            if (shift){
                keybd_event(VK_SHIFT, 0, 0, 0);
            }
            Sleep(70+ Random::getInstance()->getIntRandom(50));
            keybd_event(vkey, 0, 0, 0);
             Sleep(70+ Random::getInstance()->getIntRandom(50));
            keybd_event(vkey, 0, KEYEVENTF_KEYUP, 0);
             Sleep(70);
            if (shift+ Random::getInstance()->getIntRandom(50)){
                keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);
            }

        }
    }
}
void Win32Util::keyboardClick(unsigned char keyCode1, unsigned char keyCode2)
{
    Sleep(70+ Random::getInstance()->getIntRandom(50));
    keybd_event(keyCode1, 0, 0, 0); //按下键1
    Sleep(70+ Random::getInstance()->getIntRandom(50));
    keybd_event(keyCode2, 0, 0, 0); //按下键2
    Sleep(70+ Random::getInstance()->getIntRandom(50));
    keybd_event(keyCode2, 0, KEYEVENTF_KEYUP, 0); //释放键2
    Sleep(70+ Random::getInstance()->getIntRandom(50));
    keybd_event(keyCode1, 0, KEYEVENTF_KEYUP, 0);//释放键1
}

bool Win32Util::setSetWindowPos(){
    return SetWindowPos(GameManager::getInstantce()->wHandle, HWND_TOP, GAME_WINDOWS_X, GAME_WINDOWS_Y,GAME_WINDOWS_WIDTH,GAME_WINDOWS_HEIGHT, SWP_NOSIZE|SWP_SHOWWINDOW);
}

/**
 * 切换敌人，同时检测是否还有敌人
 * @brief Win32Util::switchEnemy
 */
void Win32Util::switchEnemy()
{
    keyboardClick(VK_CONTROL,VK_TAB);
}

QString Win32Util::getClipboard()
{
    const QClipboard *clipboard = QApplication::clipboard(); //获取剪切版内容
    const QMimeData *mimeData = clipboard->mimeData();
    if(mimeData->hasText()){
        return mimeData->text();
    }
    return "剪切板为空";
}

void Win32Util::pasteClipboard()
{

}

HWND Win32Util::findWind(QString className)
{
   return FindWindowW((LPCWSTR)className.unicode(), NULL);

}

QList<DWORD> &Win32Util::findPidProcessName(QString processName)
{
    QList<DWORD> *list = new QList<DWORD>();
    //获取所有进程
    HANDLE  processAll = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
    //进程信息
    PROCESSENTRY32W processInfo = {0};
    processInfo.dwSize = sizeof(PROCESSENTRY32W);
    do{
        if(QString::compare(processName, QString::fromWCharArray(processInfo.szExeFile))==0){

            list->append(processInfo.th32ProcessID);
        }
    }while(Process32Next(processAll, &processInfo));
    CloseHandle(processAll);
    return *list;

}

qulonglong Win32Util::getBaseAddress(QString processName, QString moduleName)
{
    QList<DWORD> &processIds = findPidProcessName(processName);
    if(processIds.isEmpty()){
        qDebug()<< "目标进程未启动";
        return 0;
    }

    foreach (DWORD processId, processIds) {
        HANDLE hModuleAll = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, processId);
        MODULEENTRY32W module = {0};
        module.dwSize = sizeof(MODULEENTRY32W);
        do{
            qDebug()<< QString::fromWCharArray(module.szModule);
            if(QString::compare(moduleName, QString::fromWCharArray(module.szModule))==0){
                qDebug()<<moduleName<< "的基址为:"<< module.hModule;
                return (qulonglong)module.modBaseAddr;
            }
        }while(Module32Next(hModuleAll, &module));
        CloseHandle(hModuleAll);
    }
    return 0;
}

//DWORD Win32Util::getTargetAddress(HANDLE &hProcess, DWORD dwBase, int Numb, ...)
//{
//    DWORD Address = dwBase;
//    va_list dw_Ptr;
//    va_start(dw_Ptr, Numb);
//    for (int nArg = 0; nArg <= Numb; nArg++)
//    {
//        if (!nArg){
//            qDebug() << "Address" << Address;
//            ReadProcessMemory(hProcess, (DWORD*)(Address), &Address, sizeof(DWORD), 0);
//        }
//        DWORD Dr = va_arg(dw_Ptr, DWORD);
//        if (nArg < Numb - 1){
//            ReadProcessMemory(hProcess, (DWORD*)(Address + Dr), &Address, sizeof(DWORD), 0);
//        }else if(nArg == Numb -1){
//            return Address + Dr;
//        }
//    }

//    va_end(dw_Ptr);
//    return Address;
//}

DWORD Win32Util::getMapNameAddress(HANDLE &hProcess, DWORD dwBase, DWORD address1, DWORD address2, DWORD address3, DWORD address4,DWORD address5)
{
    DWORD Address = dwBase;
    DWORD content = NULL;
    ReadProcessMemory(hProcess, (DWORD*)Address, &content, sizeof(Address), 0);
    Address = content;
    ReadProcessMemory(hProcess, (DWORD*)(Address + address1), &content, sizeof(Address), 0);
    Address = content;
    ReadProcessMemory(hProcess, (DWORD*)(Address + address2), &content, sizeof(Address), 0);
    Address = content;
    ReadProcessMemory(hProcess, (DWORD*)(Address + address3), &content, sizeof(Address), 0);
    Address = content;
    ReadProcessMemory(hProcess, (DWORD*)(Address + address4), &content, sizeof(Address), 0);
    Address = content;
    return Address + address5;

}

DWORD Win32Util::getTargetAddress(HANDLE &hProcess, DWORD dwBase, int Numb, ...)
{
    DWORD Address = dwBase;
    DWORD content;
    va_list dw_Ptr;
    va_start(dw_Ptr, Numb);
    for (int nArg = 0; nArg < Numb; nArg++)
    {
        if(nArg < Numb - 1){
            DWORD Dr = va_arg(dw_Ptr, DWORD);
            ReadProcessMemory(hProcess, (DWORD *)(Address + Dr), &content, sizeof(Address), 0);
            Address = content;
        }
    }
    DWORD Dr = va_arg(dw_Ptr, DWORD);
    va_end(dw_Ptr);
    return Address + Dr;

}

static BOOL CALLBACK EnumChildProc(HWND hwndChild, LPARAM lParam)
{
    qDebug() << "hwndChild=="<<Win32Util::getWindowTextW(hwndChild);

    return TRUE;
}

QRect Win32Util::getGameRect()
{
    QRect rect;
    HWND hWnd = Win32Util::findWind(TLBB_GAME_CLASS_NAME);
    if(hWnd == 0){
        return  rect;
    }
    RECT r = RECT();
    GetWindowRect(hWnd, &r);
    rect.setLeft(r.left);
    rect.setTop(r.top);
    rect.setRight(r.right);
    rect.setBottom(r.bottom);
    return rect;
}
